package org.lc.eic.messageconstruct.requestreply.jaxb.impl;

import java.sql.Timestamp;
import java.util.GregorianCalendar;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.lc.eic.messageconstruct.jaxb.content.ContentDecoder;
import org.lc.eic.messageconstruct.jaxb.content.ContentEncoder;
import org.lc.eic.messageconstruct.jaxb.content.ContentMapper;
import org.lc.eic.messageconstruct.requestreply.jaxb.exception.JAXBReplyMappingException;
import org.lc.eic.messgeconstruct.requestreply.History;
import org.lc.eic.messgeconstruct.requestreply.HistoryEntry;
import org.lc.eic.messgeconstruct.requestreply.Reply;
import org.lc.reply._1_0.ContentType;
import org.lc.reply._1_0.EntryType;
import org.lc.reply._1_0.HistoryType;
import org.lc.reply._1_0.ObjectFactory;
import org.w3c.dom.Element;

public class JAXBReplyMapping<O> {
	
	
	private ContentMapper contentMapper = new ContentMapper();
	

	public void setContentMapper(ContentMapper contentMapper) {
		this.contentMapper = contentMapper;
	}



	public Reply<O> toReply(org.lc.reply._1_0.Reply jaxbReply) throws Exception {

		Reply<O> reply = new Reply<O>();

		reply.setDestination(jaxbReply.getDestination());
		reply.setUniqueID(jaxbReply.getUniqueID());
		
		ContentDecoder<O> contentDecoder = (ContentDecoder<O>) contentMapper.getContentDecoder(jaxbReply.getContentType());
		
		if(contentDecoder == null){
			throw new JAXBReplyMappingException("No content-mapping found for content-type: "+jaxbReply.getContentType());
		}
		
		
		reply.setContent( contentDecoder.decodeContent(jaxbReply.getContent().getAny()) );
				
		reply.setContentType( reply.getContent().getClass().getName() );

		reply.setTimestamp(new Timestamp(jaxbReply.getTimestamp()
				.toGregorianCalendar().getTimeInMillis()));

		reply.setExpiration(new Timestamp(jaxbReply.getExpiration()
				.toGregorianCalendar().getTimeInMillis()));

		reply.setCorrelationID(jaxbReply.getCorrelationID());

		

		History history = new History();

		for (Object obj : jaxbReply.getHistory().getEntry()) {
			EntryType jaxbEntry = (EntryType) obj;

			HistoryEntry entry = new HistoryEntry();
			entry.setMessage(jaxbEntry.getMessage());

			entry.setTimestamp(new Timestamp(jaxbEntry.getTimestamp()
					.toGregorianCalendar().getTimeInMillis()));

			history.addEntry(entry);
		}

		reply.setHistory(history);

		return reply;

	}

	

	public org.lc.reply._1_0.Reply toJAXBReply(Reply reply)
			throws Exception {

		ObjectFactory objFactory = new ObjectFactory();

		org.lc.reply._1_0.Reply jaxbReply = objFactory.createReply();

		jaxbReply.setDestination(reply.getDestination());
		jaxbReply.setUniqueID(reply.getUniqueID());
		jaxbReply.setCorrelationID(reply.getCorrelationID());
		

		ContentType jaxbContent = objFactory.createContentType();

		Object ReplyContent = reply.getContent();
		
	
		
		ContentEncoder contentEncoder = null;
		
		if(reply.getContentType() != null){
			contentEncoder = contentMapper.getContentEncoder(reply.getContentType());
			
			if(contentEncoder == null){
				throw new JAXBReplyMappingException("No content-mapping found for content-type: "+reply.getContentType());
			}
			
		} else{
			contentEncoder = contentMapper.getContentEncoder(reply.getContent().getClass().getName());
			
			if(contentEncoder == null){
				throw new JAXBReplyMappingException("No content-mapping found for java-type: "+reply.getContent().getClass().getName());
			}
		}
		
		
		Element elementContent = contentEncoder.encodeContent(ReplyContent);

		jaxbContent.setAny( elementContent );

		jaxbReply.setContent(jaxbContent);
		jaxbReply.setContentType(elementContent.getNamespaceURI());

		jaxbReply.setTimestamp(mapTimestamp(reply.getTimestamp()));
		jaxbReply.setExpiration(mapTimestamp(reply.getExpiration()));

		

		HistoryType jaxbHistory = objFactory.createHistoryType();

		for (HistoryEntry entry : reply.getHistory().getEntries()) {

			EntryType jaxbEntry = objFactory.createEntryType();
			jaxbEntry.setMessage(entry.getMessage());

			jaxbEntry.setTimestamp(mapTimestamp(entry.getTimestamp()));

			jaxbHistory.getEntry().add(jaxbEntry);
		}

		jaxbReply.setHistory(jaxbHistory);

		return jaxbReply;

	}

	private XMLGregorianCalendar mapTimestamp(Timestamp timestamp) throws DatatypeConfigurationException {
		GregorianCalendar gregorianCalendar = new GregorianCalendar();
		gregorianCalendar.setTimeInMillis(timestamp.getTime());
		
		return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
	}

}
